For given a tuple, you need create a generic
Length
, pick the length of the tuple
給定一個元組,實現一個泛型 Length
,用來提取該元組的長度。
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']
type teslaLength = Length<tesla> // expected 4
type spaceXLength = Length<spaceX> // expected 5
接下來,你的任務是讓下面的type cases測試通過:
const tesla = ['tesla', 'model 3', 'model X', 'model Y'] as const
const spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT'] as const
type cases = [
Expect<Equal<Length<typeof tesla>, 4>>,
Expect<Equal<Length<typeof spaceX>, 5>>,
]
在這一關中,我們可以從以下幾個方向來思考:
T
是一個 tuple ?我們將會用到:
readonly
關鍵字確保元組的元素是不可變的,即它的內容無法被修改。在這裡使用 readonly 是為了更準確地確保 T
是一個 tuple (元組)
,而不是普通的陣列extends 在第三關已經介紹過,可以回到第三關參考喔!
在開始之前,讓我們先來看看如何定義和處理 tuple / array。
使用 as const
將 tesla 定義為 readonly ["tesla", "model 3", "model X", "model Y"]
,這意味著這是一個 readonly tuple 只讀元組。這樣的定義使得元組的每個元素和長度都是固定的,無法被修改。
當我們用 Length2<T extends any[]>
來獲取長度時,會出現錯誤,因為 Length2
要求 T
是可變的數組(any[]
)。但 tesla 變成了只讀類型,TypeScript 不允許將 readonly
的元組賦值給可變數組。
這個錯誤提示我們 readonly ["tesla", "model 3", "model X", "model Y"]
不能滿足 any[]
的約束,因為它是不可變的。為了解決這個問題,可以將 Length2 的約束改為 readonly any[]
,這樣就可以正常處理只讀元組,返回元組的長度。
解法1:
type Length<T extends readonly any[]> = T['length']
細節分析:
T extends readonly any[]
:這部分確保了 T 是一個只讀的陣列或元組。通過加入 readonly
,我們保證 T 的元素是不可變的,這在處理元組時尤為重要,因為元組是固定長度且元素類型明確的數組。使用 readonly 的原因是它限制了數組或元組的可變性,避免誤將元組視作普通的可變數組。
readonly
:元組的特性在於它的固定長度和不變的元素類型。readonly
可以進一步加強這個特性,確保編譯器理解我們正在處理的是元組而非普通陣列。這樣做還能防止數組內容被修改,保證類型推斷的精確性。普通陣列的長度和元素類型都可以變動,而我們需要一個穩定、不可變的結構來確保正確的類型操作。any[]
:這個語法代表一個可以包含任何類型的陣列或元組。通過這樣的約束,我們確保泛型 T
必須是符合這個形狀的,也就是說,T
必須是一個陣列或元組,不允許傳入非陣列的類型。T['length']
:這是 TypeScript 中的一種索引類型語法,它允許我們直接訪問元組或陣列的 length
屬性。每個元組和陣列在 TypeScript 中都有一個內建的 length
屬性,用來表示它的長度。在這裡,我們使用 T['length']
來提取元組 T 的長度。
type arr = [1, 2, 3];
type lengthOfArr = arr['length']; // 3
這樣,我們就能順利通過測試啦 🎉 😭 🎉
本次介紹了 Length of Tuple
的實作,下一關會挑戰 exclude
,期待再相見!